/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.Arrays;
import java.util.Random;

class Obj {
    public double value;
    Obj(double value) {
        this.value = value;
    }
}
class ArrayAccess {
    public static int input =3000000;

    public static int[] GenerateFakeRandomInteger() {
        int[] resource = new int[]{12, 43, 56, 76, 89, 54, 45, 32, 35, 47, 46, 44, 21, 37, 84};
        return resource;
    }

    public static double[] GenerateFakeRandomFloat() {
        double[] resource = new double[]{12.2, 43.5, 56.2, 76.6, 89.7, 54.9, 45.2, 32.5, 35.6, 47.2, 46.6, 44.3, 21.2, 37.6, 84.57};
        return resource;
    }

    public static boolean[] GenerateFakeRandomBool() {
        boolean[] resource = {
        true, false, true, false, true, false, true, false, true, false, true, false, true, false, true};
        return resource;
    }

    public static String[] GenerateFakeRandomString() {
        String[] resource = {
        "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op", "HOS", "Op"};
        return resource;
    }

    public static int[] GenerateFakeRandomIndex() {
        int[] resource = new int[]{3, 14, 44, 25, 91, 38, 82, 88, 64, 81, 70, 90, 33, 63, 70};
        return resource;
    }

    // primitive array
    public static void IntegerArray() {
        int count = 3000000;
        int[] integerIndexes = GenerateFakeRandomIndex();
        int[] resources = GenerateFakeRandomInteger();
        int[] res = new int[]{0, 0, 0, 0, 0};
        int num = 1;
        double start = System.nanoTime();
        int length = resources.length - 1;
        int resLength = res.length - 1;
        for (int i = 0; i < count; i++) {
            num += integerIndexes[i % num & length];
            res[i & resLength] = resources[i % num & length];
        }
        double end = System.nanoTime();
        int tmp = 1;
        for (int i = 0; i < 5; i++) {
            tmp += res[i];
        }
        System.out.println("" + tmp);
        double time = (end - start)  / 1000000;
        System.out.println("Array Access - IntegerArray:\t"+time+"\tms");
    }

    public static void FloatArray() {
        int count = 3000000;
        double[] res = new double[]{0.0, 0.0, 0.0, 0.0, 0.0};
        double[] resources = GenerateFakeRandomFloat();
        int[] integerIndexes = GenerateFakeRandomIndex();
        int num = 1;
        double start = System.nanoTime();
        int length = resources.length - 1;
        int resLength = res.length - 1;
        for (int i = 0; i < count; i++) {
            num += integerIndexes[i % num & length];
            res[i & resLength] = resources[i % num & length];
        }
        double end = System.nanoTime();
        double tmp = 0.0;
        for (int i = 0; i < 5; i++) {
            tmp += res[i];
        }
        System.out.println("" + tmp);
        double time = (end - start)  / 1000000;
        System.out.println("Array Access - FloatArray:\t"+time+"\tms");
    }

    public static void BoolArray() {
        int count = 3000000;
        boolean[] resources =GenerateFakeRandomBool();
        int[] integerIndexes = GenerateFakeRandomIndex();
        int[] res = new int[]{0, 0, 0, 0, 0};
        int num = 1;
        double start = System.nanoTime();
        int length = resources.length - 1;
        int resLength = res.length - 1;
        for (int i = 0; i < count; i++) {
            num += integerIndexes[i % num & length];
            if (resources[i % num & length]) {
                res[i & resLength] = integerIndexes[i & length];
            }
        }
        double end = System.nanoTime();
        int tmp = 0;
        for (int i = 0; i < 5; i++) {
            tmp += res[i];
        }
        System.out.println("" + tmp);
        double time = (end - start)  / 1000000;
        System.out.println("Array Access - BoolArray:\t"+time+"\tms");
    }

    public static void StringArray() {
        int count = 3000000 / 100;
        String[] resources = GenerateFakeRandomString();
        int[] res = {0, 0, 0};
        double start = System.nanoTime();
        for (int i = 0; i < count; i++) {
            res[i % res.length] += resources[i % 15].length();
        }
        double end = System.nanoTime();
        int sum = 0;
        for (int i = 0; i < res.length; i++) {
            sum += res[i];
        }
        System.out.println("" + sum);
        double time = (end - start)  / 1000000;
        System.out.println("Array Access - StringArray:\t"+time+"\tms");
    }

    public static Obj[] GenerateFakeRandomObject() {
        Obj[] resource =new Obj[15];
        Arrays.fill(resource, new Obj(0.0));
        Random random = new Random();
        for (int i = 0; i < 15; i++) {
            double randomNum = random.nextDouble() * 9 + 1;
            resource[i] = new Obj(randomNum);
        }
        return resource;
    }

    // object array
    public static void ObjectArray() {
        int count = 3000000;
        // let res: number = 1;
        Obj[] res = {new Obj(0.0), new Obj(0.0), new Obj(0.0), new Obj(0.0), new Obj(0.0)};
        // let res: Obj[] =  [new Obj(0), new Obj(0), new Obj(0), new Obj(0), new Obj(0)];
        Obj[] resources = GenerateFakeRandomObject();
        double start = System.nanoTime();
        for (int i = 0; i < count; i++) {
            // res += resources[i % res % 15].value
            res[i % 5] = resources[i % 15];
        }
        double end = System.nanoTime();
        // print(res)
        double tmp = 1;
        for (int i = 0; i < 5; i++) {
            tmp += res[i].value;
        }
        System.out.println("" + tmp);
        double time = (end - start)  / 1000000;
        System.out.println("Array Access - ObjectArray:\t"+time+"\tms");
    }
}

class Benchmark {
    public static void main(String[] args) {
        ArrayAccess.IntegerArray();
        ArrayAccess.FloatArray();
        ArrayAccess.BoolArray();
        ArrayAccess.StringArray();
        ArrayAccess.ObjectArray();
    }
}
